package cn.assumejson.springframework.context.context.annotation;

import cn.assumejson.springframework.beans.factory.config.BeanDefinition;
import cn.assumejson.springframework.beans.factory.support.BeanDefinitionRegistry;
import cn.assumejson.springframework.context.stereotype.Component;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;

import java.beans.Introspector;
import java.util.Set;

/**
 * 读取扫描路径
 * TODO 剩下的注解
 * <p>
 * A bean definition scanner that detects bean candidates on the classpath,
 * registering corresponding bean definitions with a given registry ({@code BeanFactory}
 * or {@code ApplicationContext}).
 *
 * <p>Candidate classes are detected through configurable type filters. The
 * default filters include classes that are annotated with Spring's
 * {@link cn.assumejson.springframework.context.stereotype.Component @Component},
 * {@link org.springframework.stereotype.Repository @Repository},
 * {@link org.springframework.stereotype.Service @Service}, or
 * {@link org.springframework.stereotype.Controller @Controller} stereotype.
 *
 * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
 * JSR-330's {@link javax.inject.Named} annotations, if available.
 *
 * @author Mr. Li
 * @version 1.0
 * @see AnnotationConfigApplicationContext#scan
 * @see cn.assumejson.springframework.context.stereotype.Component
 * @see org.springframework.stereotype.Repository
 * @see org.springframework.stereotype.Service
 * @see org.springframework.stereotype.Controller
 * @since 1.0 2021/12/2 22:34
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    /**
     * 定义 是否支持注解
     */
    private boolean includeAnnotationConfig = true;

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    // 扫描类
    public void scan(String... basePackages) {
        // 这里可以计算出Mapper 的加载个数
        doScan(basePackages);

        // 注册系统中的配置类处理器
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
    }

    private void doScan(String[] basePackages) {
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = findCandidateComponents(basePackage);
            for (BeanDefinition bd : candidateComponents) {
                // 跳过抽象类，接口类
                Class<?> beanClass = bd.getBeanClass();
                if (beanClass.isInterface() || ClassUtil.isAbstract(beanClass)) {
                    continue;
                }
                // 解析BeanDefinition的作用
                String beanScope = resolveBeanScope(bd);
                if (StrUtil.isNotBlank(beanScope)) {
                    bd.setScope(beanScope);
                }
                registry.registerBeanDefinition(determineBeanName(bd), bd);
            }
        }
    }

    private String determineBeanName(BeanDefinition bd) {
        // 判断是否存在@Component注解是否有别名
        Class<?> beanClass = bd.getBeanClass();
        String value = beanClass.getAnnotation(Component.class).value();
        if (StrUtil.isBlank(value)) {
            value = Introspector.decapitalize(beanClass.getSimpleName());
        }
        return value;
    }

    /**
     * 解析BeanDefinition的作用域
     *
     * @param bd beanDefinition
     * @return String
     */
    private String resolveBeanScope(BeanDefinition bd) {
        Class<?> beanClass = bd.getBeanClass();
        Scope scope = beanClass.getAnnotation(Scope.class);
        if (null != scope) return scope.value();
        return StrUtil.EMPTY;
    }

    /**
     * Specify whether to register annotation config post-processors.
     * <p>The default is to register the post-processors. Turn this off
     * to be able to ignore the annotations or to process them differently.
     */
    public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
        this.includeAnnotationConfig = includeAnnotationConfig;
    }


}
